package com.yourenbang.lingyun.transaction.web.service.impl.yxy;

import com.alibaba.fastjson.JSONObject;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.Constant;
import com.yourenbang.lingyun.constants.enums.ChannelIdEnums;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.ShareLevelRateTypeEnums;
import com.yourenbang.lingyun.constants.enums.mq.MqEnum;
import com.yourenbang.lingyun.constants.enums.table.MerchantEnum;
import com.yourenbang.lingyun.constants.enums.table.PayTransactionEnum;
import com.yourenbang.lingyun.core.base.bean.SpringContextUtils;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.StringUtils;
import com.yourenbang.lingyun.core.util.date.LocalDateUtils;
import com.yourenbang.lingyun.core.util.redis.KlksRedisUtils;
import com.yourenbang.lingyun.domain.*;
import com.yourenbang.lingyun.mapper.Merchant21Mapper;
import com.yourenbang.lingyun.mapper.MerchantPledgeCashPolicyMapper;
import com.yourenbang.lingyun.mapper.PayTransactionIndexMapper;
import com.yourenbang.lingyun.mapper.Terminal21Mapper;
import com.yourenbang.lingyun.transaction.constant.LklTransTypeEnum;
import com.yourenbang.lingyun.transaction.mapper.TransactionPayTransactionMapper;
import com.yourenbang.lingyun.transaction.util.PayTransactionUtil;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.MqPayTransationDTO;
import com.yourenbang.lingyun.transaction.web.service.impl.pay.transaction.PayTransactionConfig;
import com.yourenbang.lingyun.transaction.web.service.pay.PayTransactionOrderService;
import com.yourenbang.lingyun.transaction.web.service.pay.klks.PayEposService;
import com.yourenbang.lingyun.transaction.web.service.pay.klks.PayP35Service;
import com.yourenbang.lingyun.transaction.web.service.yxy.YxyTradeJhmpService;
import com.yourenbang.lingyun.transaction.web.service.yxy.YxyTradeService;
import com.yourenbang.mcenter.api.model.dto.MqSendMessage;
import com.yourenbang.mcenter.api.service.McenterMqService;
import com.yourenbang.merchant.api.model.dto.CheckActiveRewardYxyDTO;
import com.yourenbang.merchant.api.model.dto.CreateRewardYxyDTO;
import com.yourenbang.merchant.api.model.dto.SaveMerchantDTO;
import com.yourenbang.merchant.api.model.dto.YsPaySaveMerchantDTO;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyApiService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyRewardApiService;
import com.yourenbang.terminal.api.model.dto.RpcYxyCallbackBindDTO;
import com.yourenbang.terminal.api.model.dto.RpcYxyTerminalBindDTO;
import com.yourenbang.terminal.api.service.RpcYxyTerminalService;
import com.yourenbang.transaction.api.model.vo.pay.PayTransaction;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Date 2021/4/26 15:13
 * @Created by Jason
 */
@Slf4j
@Service
public class YxyTradeJhmpServiceImpl implements YxyTradeJhmpService {

    private static final BigDecimal REACH_AMT = new BigDecimal("600000");
    private static final BigDecimal HIERARCHY_REWARD_NEW_POLICY = new BigDecimal("25");
    private static final BigDecimal REWARD_AMT = new BigDecimal("100");
    private static final String SFT_SUCCESS_CODE = "00";
    private static final String M40_DISCOUNT_RATE_PUSH = "您已成功开通优惠费率，优惠期间享受单笔≤300元，单月≤3万元的零费率优惠政策";

    @Autowired
    private MerchantYxyApiService merchantYxyApiService;
    @Autowired
    private PayTransactionOrderService payTransactionOrderService;
    @Autowired
    private MerchantYxyRewardApiService merchantYxyRewardApiService;
    @Autowired
    private McenterMqService mcenterMqService;
    @Autowired
    private PayTransactionIndexMapper payTransactionIndexMapper;
    @Autowired
    private TransactionPayTransactionMapper transactionPayTransactionMapper;
    @Autowired
    private Merchant21Mapper merchant21Mapper;
    @Autowired
    private RpcYxyTerminalService rpcYxyTerminalService;
    @Autowired
    private PayEposService payEposService;
    @Autowired
    KlksRedisUtils klksRedisUtils;

    @Autowired
    PayP35Service payP35Service;

    @Resource
    Terminal21Mapper terminal21Mapper;
    @Resource
    MerchantPledgeCashPolicyMapper merchantPledgeCashPolicyMapper;

    @Override
    @Transactional
    public PayTransaction saveTrade(PayTransaction payTransaction) {
        PayTransactionIndexExample payTransactionIndexExample = new PayTransactionIndexExample();
        payTransactionIndexExample.createCriteria()
                .andOrderNoEqualTo(payTransaction.getOrderNo())
                .andPlatNoEqualTo(PlatNoEnums.YXY.getCode())
                .andChannelIdEqualTo(payTransaction.getChannelId());
        List<PayTransactionIndex> payTransactionIndices = payTransactionIndexMapper.selectByExample(payTransactionIndexExample);
        if (payTransactionIndices.isEmpty()) {
            payTransactionIndexMapper.insertSelective(payTransactionOrderService.getPayTransactionIndexByPayTransaction(payTransaction));
        } else {
            //推送交易状态成功且库中交易不为成功
            if (PayTransactionEnum.TransactionStatus.STATUS_10.isEquals(payTransaction.getStatus())
                    && !payTransaction.getStatus().equals(payTransactionIndices.get(0).getStatus())) {
                KLog.info("重复推送交易,状态不一致,更新:{}", payTransaction.toJSON());
                PayTransactionIndex payTransactionIndexByPayTransaction = payTransactionOrderService.getPayTransactionIndexByPayTransaction(payTransaction);
                payTransactionIndexByPayTransaction.setPayTransactionIndexId(payTransactionIndices.get(0).getPayTransactionIndexId());
                int i = payTransactionIndexMapper.updateByPrimaryKeySelective(payTransactionIndexByPayTransaction);
                BizAssertUtils.assertOne(i, "更新交易失败");
            } else {
                KLog.info("重复推送交易,不处理:{}", payTransaction.toJSON());
            }
        }
        PayTransaction byOrderNo = transactionPayTransactionMapper
                .getByOrderNo(PayTransactionConfig.getTransTableIndex(payTransaction.getUserBaseId()), payTransaction.getOrderNo());

        if (Objects.isNull(byOrderNo)) {
            transactionPayTransactionMapper.insert(PayTransactionConfig.getTransTableIndex(payTransaction.getUserBaseId()), payTransaction);
        } else {
            PayTransaction oldOrder = transactionPayTransactionMapper.getByOrderNo(PayTransactionConfig.getTransTableIndex(payTransaction.getUserBaseId()),
                    payTransaction.getOrderNo());
            //如果第一次推送是成功订单,第二次重复推送不处理
            if (!PayTransactionEnum.TransactionStatus.STATUS_10.isEquals(oldOrder.getStatus())) {
                payTransaction.setPayTransactionId(oldOrder.getPayTransactionId());
                transactionPayTransactionMapper.updateByIdNoVersion(PayTransactionConfig.getTransTableIndex(payTransaction.getUserBaseId()), payTransaction);
            } else {
                KLog.info("重复推送交易,不处理:{}", payTransaction.toJSON());
                payTransaction = null;
            }
        }
        return payTransaction;
    }

    @Override
    public Result jhmpDealTrade(JSONObject dto) {
        KLog.info("聚合码牌交易 入参:{}", dto.toJSONString());
        try {
            String merchantNo = dto.getString("MerchantNo");
            String transactionTime = dto.getString("TradeTime");
            Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(merchantNo);

            if (Objects.isNull(merchant21)) {
                log.error("聚合码牌交易,商户不存在.");
                return Result.builder().fail();
            }
            dto.put("channelId", merchant21.getChannelId());

            Terminal21 terminal21 = terminal21Mapper.selectByPrimaryKey(merchant21.getTerminalId());
            if (Objects.isNull(terminal21)) {
                log.error("聚合码牌交易,机具不存在.");
                return Result.builder().fail();
            }

            boolean toBind = Boolean.FALSE;
            MerchantPledgeCashPolicy merchantPledgeCashPolicy = merchantPledgeCashPolicyMapper.selectByPrimaryKey(terminal21.getMerchantPledgeCashPolicyId());
            Integer transactionId = transactionPayTransactionMapper.existTransactionByMerchant(PayTransactionUtil.getTransTableIndex(terminal21.getBindUserBaseId()), merchantNo);

            PayTransaction payTransaction = payTransactionFormatZfAndYs(dto, merchant21);
            // 首次交易
            if (Objects.isNull(transactionId) && BigDecimal.ZERO.compareTo(merchantPledgeCashPolicy.getPledgeCashPayAmount())==0) {
                log.info("首次交易，去绑机");
                toBind = Boolean.TRUE;
            } else if (BigDecimal.ZERO.compareTo(merchantPledgeCashPolicy.getPledgeCashPayAmount()) < 0 &&
                    LklTransTypeEnum.TYPE_412001.getTransType().equals(payTransaction.getTransType())) {
                toBind = Boolean.TRUE;
                log.info("押金交易，去绑机");
            }

            if (toBind) {
                Result bindResult = bindAndCreateReward(merchantNo, terminal21.getTerminalSn(), transactionTime, merchant21.getUserBaseId(), terminal21.getChannelId());
                if (bindResult.isFail()) {
                    log.error("聚合码牌交易, 调用Rpc接口绑机失败");
                    return Result.builder().fail();
                }
                merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(merchantNo);
            }

            //存交易
            YxyTradeService yxyTradeService = SpringContextUtils.getBean(YxyTradeService.class);
            payTransaction = yxyTradeService.saveTrade(payTransaction);

            if (Objects.nonNull(payTransaction) && LklTransTypeEnum.TYPE_412001.getTransType().equals(payTransaction.getTransType()) && (
                    MerchantEnum.PledgeCashStatusEnum.STATUS_100.getCode().equals(merchant21.getPledgeCashStatus()))) {
                Merchant21 merchant21Up = setUpdatePledgeCashMerchant(merchant21, payTransaction);
                merchant21Mapper.updateByPrimaryKeySelective(merchant21Up);
            }
            // 计入分润
            payEposService.profitOpt(payTransaction);
            //私信调用
            payEposService.sendTransactionLetter(payTransaction);
        } catch (Exception e) {
            KLog.error("聚合码牌交易处理失败:{},入参:{}", e.getMessage(), dto.toJSONString(), e);
        }
        return Result.builder().success();
    }

    /**
     * 调用绑机接口
     * @param merchantNo
     * @param sn
     * @param bindTime
     * @return
     */
    @Override
    public Result bindAndCreateReward(String merchantNo, String sn, String bindTime, String merchantUserBaseId, Short channelId) {
        // 调用绑机接口
        RpcYxyCallbackBindDTO dto = new RpcYxyCallbackBindDTO();
        dto.setMerchantNo(merchantNo);
        dto.setMerchantBindTime(LocalDateUtils.stringToLocalDateTime(bindTime));
        dto.setSn(sn);
        dto.setUserBaseId(merchantUserBaseId);
        dto.setChannelId(channelId);

        log.info("rpc调用terminal绑定机具， {}", dto);
        Result<Terminal> terminalResult = rpcYxyTerminalService.callbackBind(dto);
        if (Objects.isNull(terminalResult) || terminalResult.isFail() || Objects.isNull(terminalResult.getData())) {
            log.error("调用绑定机具失败。merchantNo={}, terminalSn={}", merchantNo, sn);
            return Result.builder().fail();
        }

        Terminal terminal = terminalResult.getData();

        // rpc调用merchant更新商户信息并关联真实用户
        SaveMerchantDTO mdto = new SaveMerchantDTO();
        mdto.setUserBaseId(terminal.getBindUserBaseId());
        mdto.setTerminalSn(terminal.getTerminalSn());
        mdto.setPushWay(SaveMerchantDTO.PUSH_WAY_POS);
        mdto.setTerminalRateId(terminal.getTerminalRateId());
        mdto.setChannelId(terminal.getChannelId());
        mdto.setBindTime(bindTime);
        mdto.setMerchantNo(merchantNo);

        Result result = merchantYxyApiService.saveMerchant(mdto);
        if (Objects.nonNull(result) && result.isSuccess()) {
            return Result.builder().success();
        } else {
            log.error("绑定机具更新商户失败。merchantNo={}, terminalSn={}", merchantNo, sn);
        }
        return Result.builder().fail();
    }


    private Merchant21 setUpdatePledgeCashMerchant(Merchant21 merchant21, PayTransaction payTransaction) {
        Merchant21 merchant21Up=new Merchant21();
        merchant21Up.setMerchantId(merchant21.getMerchantId());
        merchant21Up.setPledgeCash(payTransaction.getTransactionAmount());
        merchant21Up.setPledgeCashSuccessTime(payTransaction.getTransactionTime());
        merchant21Up.setPledgeCashOrderNo(payTransaction.getOrderNo());
        merchant21Up.setPledgeCashSerialNo(payTransaction.getOrderNo());
        merchant21Up.setPledgeCashStatus(MerchantEnum.PledgeCashStatusEnum.STATUS_200.getCode());
        return merchant21Up;
    }

    private PayTransaction payTransactionFormatHlb(JSONObject dto, Merchant21 merchant21) {
        PayTransaction payTransaction = new PayTransaction();

        payTransaction.setUserBaseId(merchant21.getUserBaseId());
        payTransaction.setMerchantId(merchant21.getMerchantId());
        payTransaction.setMerchantNo(merchant21.getMerchantNo());
        payTransaction.setMerchantName(merchant21.getMerchantName());
        payTransaction.setPhone(merchant21.getPhone());
        payTransaction.setRealName(merchant21.getRealName());
        payTransaction.setTransType(LklTransTypeEnum.TYPE_012001.getTransType());
        if (dto.getInteger("simFee") > 0){
            payTransaction.setTransType(LklTransTypeEnum.TYPE_012003.getTransType());
        }
        BigDecimal amount = dto.getBigDecimal("orderAmount");
        payTransaction.setOrderNo(dto.getString("agentOrderId"));
        payTransaction.setTransactionNo(dto.getString("agentOrderId"));
        payTransaction.setTransactionAmount(amount);
        payTransaction.setCardFlag(formatCardFlagHlb(dto.getString("posTradeType")));
        payTransaction.setSn(dto.getString("tusn"));
        payTransaction.setChannelId(ChannelIdEnums.YRB_HLB_EPOS.getCode());
        payTransaction.setTransactionBank(dto.getString("bankName"));
        payTransaction.setTransactionCardType(payTransaction.getCardFlag());
        payTransaction.setStatus(PayTransactionEnum.TransactionStatus.STATUS_10.getCode());
        payTransaction.setRate(dto.getBigDecimal("memberFeeRate").multiply(new BigDecimal("10000")).intValue());

        String transTime = dto.getString("finishDate");
        payTransaction.setTransactionTime(LocalDateUtils.parseLocalDateTimeByDefaultFormat(transTime));
        payTransaction.setTransactionMonth(StringUtils.left(StringUtils.replace(transTime,"-", ""), 6));
        payTransaction.setTransactionDay(StringUtils.left(StringUtils.replace(transTime,"-", ""), 8));
        payTransaction.setFrontSuccessTime(payTransaction.getTransactionTime());
        payTransaction.setFeeAmt(dto.getBigDecimal("singleFee"));
        payTransaction.setTransactionFee(dto.getBigDecimal("memberFee"));
        payTransaction.setPlatNo(merchant21.getPlatNo());
        payTransaction.setIsDel(false);
        payTransaction.setProfitFlag(checkIsProfitFlag(payTransaction));
        return payTransaction;
    }

    /**
     * 格式化中付银盛交易
     */
    private PayTransaction payTransactionFormatZfAndYs(JSONObject dto, Merchant21 merchant21) {
        PayTransaction payTransaction = new PayTransaction();

        payTransaction.setUserBaseId(merchant21.getUserBaseId());
        payTransaction.setMerchantId(merchant21.getMerchantId());
        payTransaction.setMerchantNo(merchant21.getMerchantNo());
        payTransaction.setMerchantName(merchant21.getMerchantName());
        payTransaction.setPhone(merchant21.getPhone());
        payTransaction.setRealName(merchant21.getRealName());
        payTransaction.setTransType(LklTransTypeEnum.TYPE_012001.getTransType());
        if (StringUtils.equals(dto.getString("OrderType"), "3")) {
            payTransaction.setTransType(LklTransTypeEnum.TYPE_412001.getTransType());
        }
        BigDecimal amount = dto.getBigDecimal("Amount");
        payTransaction.setOrderNo(dto.getString("OrderNo"));
        payTransaction.setTransactionNo(dto.getString("OrderNo"));
        payTransaction.setTransactionAmount(amount);
        payTransaction.setCardFlag(formatCardFlagZfAndYs(dto.getString("PayWay"), dto.getString("TradeType")));
        payTransaction.setSn(dto.getString("TerminalId"));
        payTransaction.setChannelId(merchant21.getChannelId());
        payTransaction.setTransactionCardType(dto.getString("TradeType"));
        payTransaction.setStatus(PayTransactionEnum.TransactionStatus.STATUS_10.getCode());
        payTransaction.setRate(new BigDecimal(StringUtils.replace(dto.getString("Rate"), "%", "")).multiply(new BigDecimal("100")).intValue());

        String transTime = dto.getString("TradeTime");
        payTransaction.setTransactionTime(LocalDateUtils.parseLocalDateTimeByDefaultFormat(transTime));
        payTransaction.setTransactionMonth(StringUtils.left(StringUtils.replace(transTime, "-", ""), 6));
        payTransaction.setTransactionDay(StringUtils.left(StringUtils.replace(transTime, "-", ""), 8));
        payTransaction.setFrontSuccessTime(payTransaction.getTransactionTime());
        payTransaction.setTransactionFee(dto.getBigDecimal("Fee"));
        payTransaction.setPlatNo(merchant21.getPlatNo());
        payTransaction.setIsDel(false);
        payTransaction.setProfitFlag(checkIsProfitFlag(payTransaction));
        return payTransaction;
    }



    private String formatCardFlagYdc(String crdFlg, String payType) {
        if ("CREDIT".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        } else if ("DEBIT".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.BORROW_CARD.getCode();
        } else if (StringUtils.startsWith(payType, "WX")) {
            return PayTransactionEnum.CardFlagEnum.WECHAT.getCode();
        } else if (StringUtils.startsWith(payType, "ZFB")) {
            return PayTransactionEnum.CardFlagEnum.ALIPAY.getCode();
        } else if (StringUtils.startsWith(payType, "YL")) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        } else {
            return payType;
        }
    }

    private String formatCardFlagHlb(String crdFlg) {
        if ("POS_CREDIT".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        } else if ("POS_DEBIT".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.BORROW_CARD.getCode();
        } else if ("WXPAY".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.WECHAT.getCode();
        } else if ("ALIPAY".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.ALIPAY.getCode();
        } else if ("POS_FLASH".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        } else if ("UNIONPAY".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        }  else if ("VIP".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        } else {
            return crdFlg;
        }
    }

    private String formatCardFlagZfAndYs(String crdFlg, String payType) {
        if ("1".equals(crdFlg)) {
            return "普通刷卡";
        } else if ("2".equals(crdFlg)) {
            return "VIP 刷卡";
        } else if ("3".equals(crdFlg)) {
            return "支付宝";
        } else if ("4".equals(crdFlg)) {
            return "微信";
        } else if ("5".equals(crdFlg)) {
            return "快捷";
        } else if ("6".equals(crdFlg)) {
            return "银联二维码";
        } else if ("7".equals(crdFlg)) {
            return "微信商家扫码";
        } else if ("8".equals(crdFlg)) {
            return "支付宝扫码";
        } else if ("9".equals(crdFlg)) {
            return "银联二维码大额";
        }
        return "未知";
    }



    /**
     * 格式化卡类型
     *
     * @param crdFlg 卡类型
     * @return 银小云卡类型
     */
    private String formatCardFlag(String crdFlg) {
        if ("01".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        } else if ("00".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.BORROW_CARD.getCode();
        } else if ("91".equals(crdFlg) || "88".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.WECHAT.getCode();
        } else if ("92".equals(crdFlg) || "89".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.ALIPAY.getCode();
        } else if ("94".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        } else if ("81".equals(crdFlg) || "22".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE_DEBIT.getCode();
        }  else if ("82".equals(crdFlg) || "21".equals(crdFlg)) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE_CREDIT.getCode();
        } else {
            return crdFlg;
        }
    }

    //判断是否计入分润  码牌不判断全部计入
    private boolean checkIsProfitFlag(PayTransaction payTransaction) {
        return true;
    }
}